﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Stonecode.Solar.ParticleEngine.Utils;
using Stonecode.Solar.ParticleEngine.ParticleSystems;
using Microsoft.Xna.Framework.Graphics;

namespace Stonecode.Solar.ParticleEngine.Emitters
{
    public class CircleEmitter : Emitter
    {
        //public Vector2 Position;
        //public float Radius;
        //public float posZ;

        public CircleEmitterTypeSettings EmitterTypeSettings { get; set; }

        //public bool RadiateOutward = true;

        public CircleEmitter(GraphicsDevice graphics, Effect pEffect, EmitterSettings psettings,
            Texture2D texture, float particlesPerSecond, Vector3 pos, float rad, Matrix view, Matrix proj)
            : base(graphics, pEffect, psettings, texture, particlesPerSecond, view, proj, EmitterType.Circle)
        {
            EmitterTypeSettings = new CircleEmitterTypeSettings(rad, true);
            Position = pos; // new Vector2(pos.X, pos.Y);
            //posZ = pos.Z;
            //Radius = rad;
        }

        public override void Dispose()
        {
            EmitterTypeSettings = null;
            base.Dispose();
        }

        private void GetPointOnCircle(out Vector2 p, out Vector2 v)
        {
            double angle;
            
            if (EmitterTypeSettings.StartAngle == EmitterTypeSettings.EndAngle)
            {
                NumberGenerator.GenerateRandomDouble(out angle);
                angle *= Math.PI * 2;
            }
            else
            {
                float ang;
                NumberGenerator.GenerateRandomFloat(EmitterTypeSettings.StartAngle, EmitterTypeSettings.EndAngle, out ang);
                angle = ang;
            }

            //float x = (float)Math.Cos(angle);
            //float y = (float)Math.Sin(angle);
            
            p = Vector2.Zero;
            p.X = ((float)Math.Cos(angle) * EmitterTypeSettings.Radius) + Position.X;
            p.Y = ((float)Math.Sin(angle) * EmitterTypeSettings.Radius) + Position.Y;

            //p = new Vector2((x * EmitterTypeSettings.Radius) + Position.X, (y * EmitterTypeSettings.Radius) + Position.Y);


            if (EmitterTypeSettings.RadiateOutward)
            {
                float randV;
                NumberGenerator.GenerateRandomFloat((float)Math.Min(_particleSystem.Settings.MinHorizontalVelocity, _particleSystem.Settings.MinVerticalVelocity),
                    (float)Math.Max(_particleSystem.Settings.MaxHorizontalVelocity, _particleSystem.Settings.MaxVerticalVelocity), out randV);
                randV = Math.Abs(randV);
                v = Vector2.Normalize(p - new Vector2(Position.X, Position.Y)) * randV;
            }
            else
            {
                NumberGenerator.GenerateRandomVector2(new Vector2(_particleSystem.Settings.MinHorizontalVelocity, _particleSystem.Settings.MinVerticalVelocity),
                    new Vector2(_particleSystem.Settings.MaxHorizontalVelocity, _particleSystem.Settings.MaxVerticalVelocity), out v);
            }
        }

        public override void Update(float dt)
        {
            if (IsAlive && Enabled && AutoGenerate)
            {
                // Work out how much time has passed since the previous update.
                //float elapsedTime = dt; //(float)gameTime.ElapsedGameTime.TotalSeconds;

                if (dt > 0)
                {
                    // If we had any time left over that we didn't use during the
                    // previous update, add that to the current elapsed time.
                    float timeToSpend = timeLeftOver + dt;

                    // Counter for looping over the time interval.
                    float currentTime = -timeLeftOver;

                    // Create particles as long as we have a big enough time interval.
                    while (timeToSpend > timeBetweenParticles)
                    {
                        currentTime += timeBetweenParticles;
                        timeToSpend -= timeBetweenParticles;

                        Vector2 position;
                        Vector2 velocity;
                        GetPointOnCircle(out position, out velocity);
                        //GetPointOnLine();

                        // Create the particle.
                        _particleSystem.AddParticleManualVelocity(new Vector3(position, Position.Z), new Vector3(velocity, 0));
                    }

                    // Store any time we didn't use, so it can be part of the next update.
                    timeLeftOver = timeToSpend;
                }

            }

            
            base.Update(dt);

        }

        public override void Trigger(float dt)
        {
            //int count = Math.Max((int)(timeBetweenParticles * ParticleSystem.Settings.ParticlesPerSecond * dt), 1);

            // If we had any time left over that we didn't use during the
            // previous update, add that to the current elapsed time.
            float timeToSpend = timeLeftOver + dt;

            // Counter for looping over the time interval.
            float currentTime = -timeLeftOver;

            //for (int i = 0; i < count; i++)
            while(timeToSpend > timeBetweenParticles)
            {
                currentTime += timeBetweenParticles;
                timeToSpend -= timeBetweenParticles;

                Vector2 position;
                Vector2 velocity;
                GetPointOnCircle(out position, out velocity);

                // Create the particle.
                _particleSystem.AddParticleManualVelocity(new Vector3(position, Position.Z), new Vector3(velocity, 0));
            }

            timeLeftOver = timeToSpend;

        }

        public override void Trigger(int particleCount)
        {
            for (int i = 0; i < particleCount; i++)
            {
                Vector2 position;
                Vector2 velocity;
                GetPointOnCircle(out position, out velocity);
                //GetPointOnLine();
                // Create the particle.
                _particleSystem.AddParticleManualVelocity(new Vector3(position, Position.Z), new Vector3(velocity, 0));
            }
        }

        public override void TriggerWithOffset(float dt, Vector2 offset)
        {
            //int count = Math.Max((int)(timeBetweenParticles * ParticleSystem.Settings.ParticlesPerSecond * dt), 1);

            float timeToSpend = timeLeftOver + dt;

            // Counter for looping over the time interval.
            float currentTime = -timeLeftOver;

            //for (int i = 0; i < count; i++)
            while (timeToSpend > timeBetweenParticles)
            {
                currentTime += timeBetweenParticles;
                timeToSpend -= timeBetweenParticles;

                Vector2 position;
                Vector2 velocity;
                GetPointOnCircle(out position, out velocity);
                
                //GetPointOnLine();

                // Create the particle.
                _particleSystem.AddParticleManualVelocity(new Vector3(position, Position.Z), new Vector3(velocity, 0));
            }

            timeLeftOver = timeToSpend;

        }

    }
}
